package core

import (
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"strconv"
	"strings"
)

type Block struct {
	data         string
	previousHash string
	hash         string
	difficulty   int
	nonce        int
}

func NewBlock(data string, previous *Block, difficulty int) (block *Block) {
	previousHash := ""
	if previous != nil {
		previousHash = previous.hash
	}
	block = &Block{data: data, previousHash: previousHash, hash: "", difficulty: difficulty, nonce: 0}
	block.mine()
	return
}

func (b *Block) computeHash() string {
	data := []byte(b.data + b.previousHash + strconv.Itoa(b.nonce))
	hash := sha256.Sum256(data)
	return hex.EncodeToString(hash[:])
}

func (b *Block) getAnswer() (answer string) {
	for i := 0; i < b.difficulty; i++ {
		answer += "0"
	}
	return
}

func (b *Block) mine() {
	prefix := b.getAnswer()
	for {
		b.nonce += 1
		b.hash = b.computeHash()
		if strings.HasPrefix(b.hash, prefix) {
			break
		}
	}
}

func (b *Block) Validate() (passed bool) {
	passed = b.hash == b.computeHash()
	return
}

func (b *Block) GetData() string { return b.data }

func (b *Block) GetPrevious() string { return b.previousHash }

func (b *Block) GetHash() string { return b.hash }

// 不允许篡改数据，此处仅用于测试`Validate`方法
//func (b *Block) SetData(data string) {
//	b.data = data
//	b.hash = b.computeHash()
//}

func (b *Block) String() string {
	return fmt.Sprintf(
		"\t{\n\t\tdata: %s\n\t\tnonce: %d\n\t\tpreviousHash: %s\n\t\thash: %s\n\t}",
		b.data, b.nonce, b.previousHash, b.hash,
	)
}
